package org.smth.search.query.impl;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.smth.search.query.QueryInfo;
import org.smth.search.query.QueryParser;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@Singleton
public class FieldQueryParser implements QueryParser {

	@Inject
	@Named("DefaultField")
	private String defaultField;

	@Inject
	private SimpleQueryParser simpleQueryParser;

	protected List<String> parseTokens_(String query) {
		List<String> tokens = new LinkedList<String>();
		StringBuffer buffer = new StringBuffer();
		int len = query.length();
		int pos = 0;
		char c;
		while (pos < len) {
			while (pos < len && ((c = query.charAt(pos)) == ' ' || c == '　')) {
				pos++;
			}
			while (pos < len && (c = query.charAt(pos)) != ' ' && c != '　') {
				buffer.append(c);
				pos++;
				if (c == '"' || c == '“') {
					boolean ok = false;
					while (!ok) {
						while (pos < len && (c = query.charAt(pos)) != '"' && c != '”') {
							buffer.append(c);
							pos++;
						}
						if (pos < len) {
							buffer.append(c);
							pos++;
						}
						ok = true;
						if (pos < len && (c = query.charAt(pos)) != ' ' && c != '　') {
							ok = false;
						}
					}
				}
			}
			if (buffer.length() > 0) {
				tokens.add(buffer.toString());
				buffer.setLength(0);
			}
		}
		return tokens;
	}

	public List<String> parseTokens(String query) {
		List<String> tokens = parseTokens_(query);
		int len = tokens.size();
		char c;
		int size;
		for (int i = 0; i < len; i++) {
			String token = tokens.get(i);
			while (token.length() > 0 && ((c = token.charAt(0)) == '"' || c == '“')) {
				token = token.substring(1);
			}
			while ((size = token.length()) > 0 && ((c = token.charAt(size - 1)) == '"' || c == '”')) {
				token = token.substring(0, size - 1);
			}
			if (size > 0) {
				tokens.set(i, token);
			} else {
				tokens.remove(i);
				i--;
				len--;
			}
		}
		return tokens;
	}

	public Query parseOneQuery(String token, List<Token> toks) {
		int index = token.indexOf(':');
		if (index < 0) {
			index = token.indexOf('：');
		}
		String field = defaultField;
		if (index > 0) {
			String f = token.substring(0, index);
			char c;
			if ((c = f.charAt(0)) < 128 && Character.isLetter(c)) {
				f = f.toLowerCase();
				if ("time".equals(f)) {
					//todo
				} else {
					field = f;
					token = token.substring(index + 1);
				}
			}
		}
		return simpleQueryParser.parseQuery(field, token, toks).getQuery();
	}

	public QueryInfo parseQuery(String q) {
		if (q == null || q.length() < 1) {
			return null;
		}
		List<String> tokens = parseTokens(q);
		if (tokens.size() > 0) {
			List<Query> querys = new ArrayList<Query>();
			List<Token> toks = new ArrayList<Token>();
			for (String s : tokens) {
				Query one = parseOneQuery(s, toks);
				if (one != null) {
					querys.add(one);
				}
			}
			if (querys.size() > 0) {
				BooleanQuery query = new BooleanQuery();
				for (Query one : querys) {
					query.add(one, BooleanClause.Occur.MUST);
				}
				return new QueryInfoImpl(query, toks);
			}
		}
		return null;
	}

}
